package com.urea.system.service.impl;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaSubscribeMessage;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.urea.common.core.domain.entity.Customer;
import com.urea.common.core.domain.entity.SysUser;
import com.urea.common.utils.SecurityUtils;
import com.urea.common.utils.StringUtils;
import com.urea.system.constants.BusinessConstants;
import com.urea.system.domain.*;
import com.urea.system.domain.event.FeeEvent;
import com.urea.system.domain.vo.*;
import com.urea.system.service.*;
import lombok.extern.java.Log;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.WxMpTemplateMsgService;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateData;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import com.urea.system.mapper.OrderMapper;
import org.springframework.transaction.annotation.Transactional;

import static com.urea.system.constants.BusinessConstants.OFFLINE_PAY;
import static com.urea.system.constants.BusinessConstants.ORDER_STATUS_COMPLETE;

/**
 * 订单Service业务层处理
 *
 * @author liuzd
 * @date 2023-08-01
 */
@Service
@Log
@Transactional
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements IOrderService {
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private IFleetUserService fleetUserService;
    @Autowired
    private WxMpService wxMpService;
    @Autowired
    private ITerminalService terminalService;
    @Autowired
    private ISysUserService sysUserService;
    @Autowired
    private IPayInfoService payInfoService;
    @Autowired
    private IPayService payService;
    @Autowired
    private ITerminalNoticeService terminalNoticeService;
    @Autowired
    private ITerminalLogService terminalLogService;
    @Autowired
    private IHardwareService hardwareService;
    @Autowired
    private ICustomerService customerService;
    @Autowired
    private WxMaService wxMaService;

    @Value("${wx.mp.templateId}")
    private String templateId;

    /**
     * 查询订单
     *
     * @param id 订单主键
     * @return 订单
     */
    @Override
    public OrderVo selectOrderById(Long id) {
        return orderMapper.selectOrderById(id);
    }

    /**
     * 查询订单列表
     *
     * @param order 订单
     * @return 订单
     */
    @Override
    public List<OrderVo> selectOrderList(Order order) {
        return orderMapper.selectOrderList(order);
    }

    /**
     * 新增订单
     *
     * @param order 订单
     * @return 结果
     */
    @Override
    public int insertOrder(Order order) {
        return orderMapper.insertOrder(order);
    }

    /**
     * 修改订单
     *
     * @param order 订单
     * @return 结果
     */
    @Override
    public int updateOrder(Order order) {
        return orderMapper.updateOrder(order);
    }

    /**
     * 批量删除订单
     *
     * @param ids 需要删除的订单主键
     * @return 结果
     */
    @Override
    public int deleteOrderByIds(Long[] ids) {
        return orderMapper.deleteOrderByIds(ids);
    }

    /**
     * 删除订单信息
     *
     * @param id 订单主键
     * @return 结果
     */
    @Override
    public int deleteOrderById(Long id) {
        return orderMapper.deleteOrderById(id);
    }

    /**
     * 根据时间汇总订单数量
     *
     * @return 结果
     */
    @Override
    public OrderVo queryStatisticsByDate(Long userId, Long agentId, Long storeId) {
        return orderMapper.queryStatisticsByDate(userId, agentId, storeId);
    }

    /**
     * pc端订单管理列表
     *
     * @param dto 查询参数
     * @return 结果
     */
    @Override
    public List<OrderDto> queryOrderList(OrderDto dto) {
        SecurityUtils.getUserIdByUserType(dto);
        return orderMapper.queryOrderList(dto);
    }

    @Override
    public OrderDto countOrders(OrderDto dto) {
        SecurityUtils.getUserIdByUserType(dto);
        return orderMapper.countOrders(dto);
    }

    /**
     * pc订单统计列表
     *
     * @param vo 查询条件
     * @return 结果
     */
    @Override
    public List<OrderStatisticsVo> statisticsList(OrderVo vo) {
        SecurityUtils.getUserIdByUserType(vo);
        if (Objects.nonNull(vo.getParams().get("fleetUserId"))) {
            FleetUser fleetUserId = fleetUserService.getOne(Wrappers.lambdaQuery(FleetUser.class)
                    .eq(FleetUser::getUid, Long.valueOf(String.valueOf(vo.getParams().get("fleetUserId")))));
            if (Objects.nonNull(fleetUserId)) {
                vo.getParams().put("fleetId", fleetUserId.getFleetId());
            }
        }
        return baseMapper.statisticsList(vo);
    }

    /**
     * ppc订单统计数据
     *
     * @param vo p
     * @return 结果
     */
    @Override
    public OrderStatisticsVo statistics(OrderVo vo) {
        SecurityUtils.getUserIdByUserType(vo);
        List<Map<String, String>> list = baseMapper.statistics(vo);
        long allCount = 0L;
        OrderStatisticsVo result = new OrderStatisticsVo();
        for (Map<String, String> map : list) {
            String method = map.get("payMethod");
            String orderCount = "0";
            String sumAmount = "0";
            if (Objects.nonNull(map.get("orderCount"))) {
                orderCount = String.valueOf(map.get("orderCount"));
            }
            if (Objects.nonNull(map.get("sumAmount"))) {
                sumAmount = String.valueOf(map.get("sumAmount"));
            }
            if (StringUtils.isNotBlank(method) && "加注".equals(method)) {
                if (StringUtils.isNotBlank(orderCount)) {
                    long l = Long.parseLong(orderCount);
                    result.setFillCount(l);
                    allCount += l;
                }
                if (StringUtils.isNotBlank(sumAmount)) {
                    result.setFillAmount(new BigDecimal(sumAmount));
                }
            }
            if (StringUtils.isNotBlank(method) && "充值".equals(method)) {
                if (StringUtils.isNotBlank(orderCount)) {
                    long l = Long.parseLong(orderCount);
                    result.setRechargeCount(l);
                    allCount += l;
                }
                if (StringUtils.isNotBlank(sumAmount)) {
                    result.setRechargeAmount(new BigDecimal(sumAmount));
                }
            }
        }
        result.setAllCount(allCount);
        return result;
    }

    /**
     * 根据类型查询总金额
     *
     * @param payMethod 订单类型
     * @return 结果
     */
    @Override
    public BigDecimal selectSumAmount(Integer payMethod) {
        return baseMapper.selectSumAmount(payMethod);
    }

    @Override
    public void saveOfflineOrder(Order offlineOrder) {
        save(offlineOrder);
    }

    @Override
    public void sendOrderMsg(String orderNo) {
        Order order = order(orderNo);
        Long terminalId = order.getTerminalId();
        TerminalVo terminalVo = terminalService.selectTerminalById(terminalId);
        Long storeUid = terminalVo.getStoreUid();
        if (Objects.nonNull(storeUid)) {
            SysUser sysUser = sysUserService.selectUserById(storeUid);
            if (StrUtil.isNotEmpty(sysUser.getOpenid())) {
                WxMpTemplateMsgService templateMsgService = wxMpService.getTemplateMsgService();
                List<WxMpTemplateData> data = new ArrayList<>();
                data.add(new WxMpTemplateData("amount2", order.getPayAmount() + "元", "#FF0000"));
                data.add(new WxMpTemplateData("time3", DateUtil.format(order.getCreatedTime(), "yyyy年MM月dd日 HH:mm:ss")));
                data.add(new WxMpTemplateData("character_string6", order.getOrderNo()));
                data.add(new WxMpTemplateData("number4", terminalVo.getTerminalNo()));
                data.add(new WxMpTemplateData("thing12", "挂抢结算"));
                WxMpTemplateMessage templateMessage = WxMpTemplateMessage.builder()
                        .toUser(sysUser.getOpenid())
                        .templateId(templateId)
                        .data(data)
                        .build();
                try {
                    templateMsgService.sendTemplateMsg(templateMessage);
                } catch (WxErrorException e) {
                    throw new RuntimeException(e);
                }
            }
        }

    }

    @Override
    public Order order(String orderNo) {
        if (StrUtil.isEmpty(orderNo)){
            return null;
        }
        return lambdaQuery().eq(Order::getOrderNo, orderNo).one();
    }

    @Override
    public void updateOrderFinish(FeeEvent feeEvent) {
        String orderNo = feeEvent.getSer();
        // 总量
        Integer amount = feeEvent.getAmount();
        // 单价
        Integer price = feeEvent.getPrice();
        // 总价 分
        Integer totalPrice = feeEvent.getPriceTotal();
        // 开始时间
        String begin = feeEvent.getBegin();
        String beginDate = "";
        String endDate = "";
        if (begin.indexOf("-")<0){
            beginDate = getFormateTime(begin);
        }
        // 结束时间
        String end = feeEvent.getEnd();
        if (end.indexOf("-")<0){
            beginDate = getFormateTime(end);
        }
        // 结束原因 2超时停止 3挂枪停止  4stop指令  5到达消费金额停止
        int resValue = feeEvent.getReason();
        String res = 2==resValue?"超时停止":3==resValue?"挂枪停止":
                4==resValue?"stop指令":"订单金额已消费完毕,自动停止";
        //  用户id
        //  String customerId = extra.getString("card");
        // 获取订单信息
        Order order = order(orderNo);
        PayInfo payInfo = payInfoService.payInfo(orderNo);
        // 更新设备当前容量
        Terminal terminal = terminalService.getById(order.getTerminalId());

        // 为空 或订单不是加注 直接结束
        if (Objects.isNull(payInfo)||!payInfo.getPayMethod().equals(BusinessConstants.BIZ_FILL)){
            log.info("################保存离线订单信息########################");
            Order offlineOrder = builderOfflineOrder(feeEvent,begin,end,terminal);
            saveOfflineOrder(offlineOrder);
            return;
        }
        // 订单已经更新完成 直接返回 避免重复消息
        if (StringUtils.isNotBlank(payInfo.getExtraInfo())){
            return;
        }

        // 加注升数
        BigDecimal fillSum = new BigDecimal(amount).divide(BigDecimal.valueOf(100L),2, RoundingMode.HALF_UP);
        // 可加注升数
        BigDecimal fillNo = new BigDecimal(totalPrice).divide(new BigDecimal(price),2,RoundingMode.HALF_UP);
        payInfoService.update(Wrappers.lambdaUpdate(PayInfo.class).eq(PayInfo::getId, payInfo.getId())
                .set(PayInfo::getExtraInfo, fillSum.toString())
                .set(PayInfo::getFillNo, fillNo));
        LambdaUpdateWrapper<Order> orderWrapper = Wrappers.lambdaUpdate(Order.class).eq(Order::getOrderNo, orderNo)
                .set(Order::getOrderDesc, JSONObject.toJSONString(feeEvent));
        BigDecimal fillAmount = new BigDecimal(totalPrice).divide(new BigDecimal("100"),2,RoundingMode.HALF_UP);
        //  如果是微信支付 订单解冻 todo 测试在支付成功以及解冻  投产 需要把那边代码注释 这边放开
//                if(order.getPayType().equals(BusinessConstants.WX_PAY)){
//                    payService.thawApply(orderNo);
//                }
        if (fillAmount.compareTo(order.getPayAmount())<0){
            BigDecimal refundAmount = order.getPayAmount().subtract(fillAmount);
            PayVo payVo = new PayVo();
            payVo.setOrderNo(orderNo);
            payVo.setRefundAmount(refundAmount);
            payService.unifyRefund(payVo);
        }
        BigDecimal rebateAmount = sysUserService.updateRebateAmount(order.getAgentId(), fillAmount);
        orderWrapper.set(Order::getRebateAmount,rebateAmount);
        update(orderWrapper);


        BigDecimal newCurr = terminal.getCurrentCapacity().subtract(fillSum);
        terminalService.update(Wrappers.lambdaUpdate(Terminal.class).eq(Terminal::getId,order.getTerminalId())
                .set(Terminal::getCurrentCapacity,newCurr));
        // 如果当前容量小于百分之50  则预警
        if (newCurr.divide(terminal.getCapacity(),2,RoundingMode.HALF_UP).compareTo(new BigDecimal("0.5"))<1){
            TerminalNotice notice = new TerminalNotice();
            notice.setTerminalId(terminal.getId());
            notice.setNoticeType(0);
            notice.setTerminalCapacity(newCurr);
            notice.setNotice("尿素容量不足");
            terminalNoticeService.save(notice);
        }
        // 记录操作日志
        TerminalLog terminalLog = new TerminalLog();
        terminalLog.setTerminalId(terminal.getId());
        terminalLog.setTerminalCapacity(newCurr);
        terminalLog.setChangeCapacity(fillSum);
        terminalLog.setOperater(String.valueOf(order.getCustomerId()));
        terminalLog.setLogType(1);
        terminalLog.setOrderNo(orderNo);
        terminalLogService.save(terminalLog);
        // 发送确认消息
        hardwareService.confirm(orderNo,String.valueOf(order.getCustomerId()),terminal.getTerminalNo());
        // 发送通知给小程序
        Customer customer = customerService.getById(order.getCustomerId());
        if (Objects.nonNull(customer)){
            // 如果用户授权则推送通知
//                    Object cacheObject = redisCache.getCacheObject(templateId.concat("@").concat(customer.getOpenId()));
//                    if (Objects.nonNull(cacheObject)){
            log.info("################发送模板消息################");
            try {
                wxMaService.getMsgService().sendSubscribeMsg(WxMaSubscribeMessage.builder()
                        .templateId(templateId)
                        .data(Lists.newArrayList(
                                new WxMaSubscribeMessage.MsgData("character_string1", terminal.getTerminalNo()),
                                new WxMaSubscribeMessage.MsgData("time2", StringUtils.isBlank(beginDate)?begin:beginDate),
                                new WxMaSubscribeMessage.MsgData("time3", StringUtils.isBlank(endDate)?end:endDate),
                                new WxMaSubscribeMessage.MsgData("amount4", fillAmount.toString()),
                                new WxMaSubscribeMessage.MsgData("thing5", res)))
                        .toUser(customer.getOpenId())
                        // 跳转页面
                        //.page()
                        .build());
            } catch (WxErrorException e) {
                throw new RuntimeException(e);
            }
        }
        //给门店发送消息
        sendOrderMsg(orderNo);

    }

    private static String getFormateTime(String begin) {
        String beginDate;
        beginDate = LocalDateTime.ofInstant(Instant.ofEpochSecond(Long.valueOf(begin)), ZoneId.systemDefault())
                .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        return beginDate;
    }

    private Order builderOfflineOrder(FeeEvent event, String begin, String endDate, Terminal terminal) {
        String orderNo = LocalDateTime.ofInstant(Instant.ofEpochSecond(Long.valueOf(begin)), ZoneId.systemDefault()).format(DateTimeFormatter.ofPattern("yyyyMMddhhmmssSSS"));
        BigDecimal fillAmount = new BigDecimal(event.getPriceTotal()).divide(new BigDecimal("100"),2,RoundingMode.HALF_UP);
        Order order = new Order();
        order.setOrderNo(orderNo);
        order.setAmount(new BigDecimal(event.getAmount()).multiply(BigDecimal.valueOf(0.01)));
        order.setPayType(OFFLINE_PAY);
        order.setTerminalId(terminal.getId());
        order.setAgentId(terminal.getAgentUid());
        order.setRefundAmount(BigDecimal.ZERO);
        order.setPayAmount(fillAmount);
        order.setRebateAmount(fillAmount);
        order.setPayTime(LocalDateTime.now());
        order.setStatus(ORDER_STATUS_COMPLETE);
        order.setStoreUid(terminal.getStoreUid());
        order.setOrderDesc(event.toString());
        return order;
    }

}
